// Copyright (c) MatrixFramework. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using MatrixFramework.Keycloak.Abstractions.Services;
using MatrixFramework.Keycloak.Abstractions.Options;
using MatrixFramework.Keycloak.Services;

namespace MatrixFramework.Keycloak.Extensions;

/// <summary>
/// MatrixFramework.Keycloak依赖注入扩展
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// 添加MatrixFramework Keycloak服务实现
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakServices(this IServiceCollection services)
    {
        // 注册Keycloak管理服务
        services.AddScoped<IKeycloakAdminService, KeycloakAdminService>();

        // 注册租户相关服务
        services.AddScoped<ITenantResolver, DefaultTenantResolver>();
        services.AddScoped<ITenantService, TenantService>();

        // 注册HTTP客户端工厂
        services.AddHttpClient<IKeycloakClientFactory, KeycloakClientFactory>();

        // 注册HttpContextAccessor（用于租户解析）
        services.AddHttpContextAccessor();

        return services;
    }

    /// <summary>
    /// 添加MatrixFramework Keycloak服务实现（带配置）
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configuration">配置</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakServices(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // 配置选项
        services.Configure<KeycloakOptions>(KeycloakOptions.SectionName, configuration);
        services.PostConfigure<KeycloakOptions>(options =>
        {
            ValidateKeycloakOptions(options);
        });

        // 注册服务
        services.AddKeycloakServices();

        return services;
    }

    /// <summary>
    /// 添加MatrixFramework Keycloak服务实现（带选项配置）
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configureOptions">配置选项</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakServices(
        this IServiceCollection services,
        Action<KeycloakOptions> configureOptions)
    {
        // 配置选项
        services.Configure(configureOptions);
        services.PostConfigure<KeycloakOptions>(options =>
        {
            ValidateKeycloakOptions(options);
        });

        // 注册服务
        services.AddKeycloakServices();

        return services;
    }

    /// <summary>
    /// 添加租户解析服务
    /// </summary>
    /// <param name="services">服务集合</param>
    /// <param name="configureProviders">配置租户提供程序</param>
    /// <returns>服务集合</returns>
    public static IServiceCollection AddKeycloakTenantResolver(
        this IServiceCollection services,
        Action<TenantProviderBuilder>? configureProviders = null)
    {
        // 注册HttpContextAccessor
        services.AddHttpContextAccessor();

        // 注册租户解析器
        services.AddSingleton<ITenantResolver>(provider =>
        {
            var logger = provider.GetService<Microsoft.Extensions.Logging.ILogger<DefaultTenantResolver>>();
            var tenantProviders = provider.GetServices<ITenantProvider>();
            return new DefaultTenantResolver(tenantProviders, logger);
        });

        // 配置租户提供程序
        if (configureProviders != null)
        {
            var builder = new TenantProviderBuilder(services);
            configureProviders(builder);
            builder.Build();
        }

        return services;
    }

    /// <summary>
    /// 验证Keycloak配置选项
    /// </summary>
    /// <param name="options">配置选项</param>
    /// <exception cref="ArgumentException">配置无效时抛出</exception>
    private static void ValidateKeycloakOptions(KeycloakOptions options)
    {
        if (string.IsNullOrWhiteSpace(options.BaseUrl))
            throw new ArgumentException("Keycloak BaseUrl 不能为空", nameof(options));

        if (!Uri.TryCreate(options.BaseUrl, UriKind.Absolute, out _))
            throw new ArgumentException("Keycloak BaseUrl 必须是有效的URI", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminClientId))
            throw new ArgumentException("AdminClientId 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminClientSecret))
            throw new ArgumentException("AdminClientSecret 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.DefaultRealm))
            throw new ArgumentException("DefaultRealm 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminUsername))
            throw new ArgumentException("AdminUsername 不能为空", nameof(options));

        if (string.IsNullOrWhiteSpace(options.AdminPassword))
            throw new ArgumentException("AdminPassword 不能为空", nameof(options));

        if (options.TimeoutSeconds < 1 || options.TimeoutSeconds > 300)
            throw new ArgumentException("TimeoutSeconds 必须在1-300秒之间", nameof(options));

        if (options.RetryCount < 0 || options.RetryCount > 10)
            throw new ArgumentException("RetryCount 必须在0-10次之间", nameof(options));

        if (options.RetryDelayMs < 100 || options.RetryDelayMs > 60000)
            throw new ArgumentException("RetryDelayMs 必须在100-60000毫秒之间", nameof(options));

        if (options.TokenExpirationBufferMinutes < 1 || options.TokenExpirationBufferMinutes > 60)
            throw new ArgumentException("TokenExpirationBufferMinutes 必须在1-60分钟之间", nameof(options));
    }
}